using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

[RequireComponent(typeof(Enemy))]
[DisallowMultipleComponent]
public class EnemyMovementAI : MonoBehaviour
{
    #region Tooltip

    [Tooltip("MovementDetailsSO 包含运动细节（如速度）的可脚本对象")]

    #endregion Tooltip

    [SerializeField]
    private MovementDetailsSO movementDetails;

    private Enemy enemy;
    private Stack<Vector3> movementSteps = new Stack<Vector3>();
    private Vector3 playerReferencePosition;
    private Coroutine moveEnemyRoutine;
    private float currentEnemyPathRebuildCooldown;
    private WaitForFixedUpdate waitForFixedUpdate;
    [HideInInspector] public float moveSpeed;
    private bool chasePlayer = false;
    [HideInInspector] public int updateFrameNumber = 1; // 默认值。 这是由敌人的刷怪者设置的。
    private List<Vector2Int> surroundingPositionList = new List<Vector2Int>();

    private void Awake()
    {
        // 加载组件
        enemy = GetComponent<Enemy>();

        moveSpeed = movementDetails.GetMoveSpeed();
    }

    private void Start()
    {
        // 创建用于协程的 waitforfixed 更新
        waitForFixedUpdate = new WaitForFixedUpdate();

        // 重置播放器参考位置
        playerReferencePosition = GameManager.Instance.GetPlayer().GetPlayerPosition();
    }

    private void Update()
    {
        MoveEnemy();
    }

    /// <summary>
    /// 使用 AStar 寻路来构建一条通往玩家的路径 - 然后将敌人移动到路径上的每个网格位置
    /// </summary>
    private void MoveEnemy()
    {
        // 移动冷却计时器
        currentEnemyPathRebuildCooldown -= Time.deltaTime;

        // 检查到玩家的距离，看看敌人是否应该开始追击
        if (!chasePlayer && Vector3.Distance(transform.position, GameManager.Instance.GetPlayer().GetPlayerPosition()) <
            enemy.enemyDetails.chaseDistance)
        {
            chasePlayer = true;
        }

        //如果距离不够近，无法追逐玩家，则返回
        if (!chasePlayer)
            return;

        // 仅在特定帧上处理 A 星路重建以在敌人之间分散负载
        if (Time.frameCount % Settings.targetFrameRateToSpreadPathfindingOver != updateFrameNumber) return;

        // 如果达到移动冷却计时器或玩家移动的距离超过要求的距离
        // 然后重建敌人的路径并移动敌人
        if (currentEnemyPathRebuildCooldown <= 0f ||
            (Vector3.Distance(playerReferencePosition, GameManager.Instance.GetPlayer().GetPlayerPosition()) >
             Settings.playerMoveDistanceToRebuildPath))
        {
            // 重置路径重建冷却计时器
            currentEnemyPathRebuildCooldown = Settings.enemyPathRebuildCooldown;

            // 重置播放器参考位置
            playerReferencePosition = GameManager.Instance.GetPlayer().GetPlayerPosition();

            // 使用 AStar 寻路移动敌人 - 触发玩家路径重建
            CreatePath();

            // 如果找到了路径，请移动敌人
            if (movementSteps != null)
            {
                if (moveEnemyRoutine != null)
                {
                    // 触发空闲事件
                    enemy.idleEvent.CallIdleEvent();
                    StopCoroutine(moveEnemyRoutine);
                }

                // 使用协程沿路径移动敌人
                moveEnemyRoutine = StartCoroutine(MoveEnemyRoutine(movementSteps));
            }
        }
    }

    /// <summary>
    /// 协程将敌人移动到路径上的下一个位置
    /// </summary>
    private IEnumerator MoveEnemyRoutine(Stack<Vector3> movementSteps)
    {
        while (movementSteps.Count > 0)
        {
            Vector3 nextPosition = movementSteps.Pop();

            // 虽然不是很接近，但继续移动 - 当接近时，进入下一步
            while (Vector3.Distance(nextPosition, transform.position) > 0.2f)
            {
                // 触发移动事件
                enemy.movementToPositionEvent.CallMovementToPositionEvent(nextPosition, transform.position, moveSpeed,
                    (nextPosition - transform.position).normalized);

                yield return waitForFixedUpdate; // 使用 2D 物理移动 enmy，因此请等到下一次固定更新
            }

            yield return waitForFixedUpdate;
        }

        // 路径结束步骤 - 触发敌人空闲事件
        enemy.idleEvent.CallIdleEvent();
    }

    /// <summary>
    /// 使用 AStar 静态类为敌人创建路径
    /// </summary>
    private void CreatePath()
    {
        Room currentRoom = GameManager.Instance.GetCurrentRoom();

        Grid grid = currentRoom.instantiatedRoom.grid;

        // 获取球员在网格上的位置
        Vector3Int playerGridPosition = GetNearestNonObstaclePlayerPosition(currentRoom);

        // 在网格上获取敌人的位置
        Vector3Int enemyGridPosition = grid.WorldToCell(transform.position);

        // 为敌人建造一条前进的道路
        movementSteps = AStar.BuildPath(currentRoom, enemyGridPosition, playerGridPosition);

        // 在路径上迈出第一步 - 这是敌人已经所在的网格方块
        if (movementSteps != null)
        {
            movementSteps.Pop();
        }
        else
        {
            // 触发空闲事件 - 无路径
            enemy.idleEvent.CallIdleEvent();
        }
    }

    /// <summary>
    /// 设置将重新计算敌人路径的帧数 - 以避免性能飙升
    /// </summary>
    public void SetUpdateFrameNumber(int updateFrameNumber)
    {
        this.updateFrameNumber = updateFrameNumber;
    }

    /// <summary>
    /// 获得离玩家最近的位置，不要在障碍物上
    /// </summary>
    private Vector3Int GetNearestNonObstaclePlayerPosition(Room currentRoom)
    {
        Vector3 playerPosition = GameManager.Instance.GetPlayer().GetPlayerPosition();

        Vector3Int playerCellPosition = currentRoom.instantiatedRoom.grid.WorldToCell(playerPosition);

        Vector2Int adjustedPlayerCellPositon = new Vector2Int(playerCellPosition.x - currentRoom.templateLowerBounds.x,
            playerCellPosition.y - currentRoom.templateLowerBounds.y);

        int obstacle =
            Mathf.Min(
                currentRoom.instantiatedRoom.aStarMovementPenalty[adjustedPlayerCellPositon.x,
                    adjustedPlayerCellPositon.y],
                currentRoom.instantiatedRoom.aStarItemObstacles[adjustedPlayerCellPositon.x,
                    adjustedPlayerCellPositon.y]);


        // 如果玩家不在标记为障碍物的单元格方块上，则返回该位置
        if (obstacle != 0)
        {
            return playerCellPosition;
        }
        // 找到一个不是障碍物的包围单元 - 这是必需的，因为使用“半碰撞”瓷砖
        // 和桌子，玩家可以在一个被标记为障碍物的网格方块上
        else
        {
            // 空的周围位置列表
            surroundingPositionList.Clear();

            // 填充周围的位置列表 - 这将包含围绕 （0,0） 网格方块的 8 个可能的矢量位置
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    if (j == 0 && i == 0) continue;

                    surroundingPositionList.Add(new Vector2Int(i, j));
                }
            }

            // 遍历所有位置
            for (int l = 0; l < 8; l++)
            {
                // 为列表生成随机索引
                int index = Random.Range(0, surroundingPositionList.Count);

                // 查看选定的周围位置是否有障碍物
                try
                {
                    obstacle = Mathf.Min(
                        currentRoom.instantiatedRoom.aStarMovementPenalty[
                            adjustedPlayerCellPositon.x + surroundingPositionList[index].x,
                            adjustedPlayerCellPositon.y + surroundingPositionList[index].y],
                        currentRoom.instantiatedRoom.aStarItemObstacles[
                            adjustedPlayerCellPositon.x + surroundingPositionList[index].x,
                            adjustedPlayerCellPositon.y + surroundingPositionList[index].y]);

                    // 如果没有障碍物，请返回要导航到的单元格位置
                    if (obstacle != 0)
                    {
                        return new Vector3Int(playerCellPosition.x + surroundingPositionList[index].x,
                            playerCellPosition.y + surroundingPositionList[index].y, 0);
                    }
                }
                // 在周围位置位于网格之外的位置捕获错误
                catch
                {
                }

                // 移除障碍物周围的位置，以便我们再试一次
                surroundingPositionList.RemoveAt(index);
            }
            
            // 如果在玩家周围没有发现非障碍物单元 - 将敌人送往敌人生成位置的方向
            return (Vector3Int)currentRoom.spawnPositionArray[Random.Range(0, currentRoom.spawnPositionArray.Length)];
        }
    }

    #region Validation

#if UNITY_EDITOR

    private void OnValidate()
    {
        HelperUtilities.ValidateCheckNullValue(this, nameof(movementDetails), movementDetails);
    }

#endif

    #endregion Validation
}